import socket
import time
import threading
from enum import Enum
import logging

class Protocol(Enum):
    TCP = 'tcp'
    UDP = 'udp'

class NetworkClient:
    def __init__(self):
        self.protocol = Protocol.TCP
        self.target_ip = ''
        self.target_port = 0
        self.socket = None
        self.connected = False
        self.reconnect_thread = None
        self.stop_event = threading.Event()
        self.lock = threading.RLock()
        self.logger = self._setup_logger()
        
    def _setup_logger(self):
        logger = logging.getLogger('NetworkClient')
        logger.setLevel(logging.DEBUG)
        handler = logging.StreamHandler()
        handler.setFormatter(logging.Formatter(
            '%(asctime)s - %(name)s - %(levelname)s - %(message)s'))
        logger.addHandler(handler)
        return logger

    def configure(self, protocol, ip, port):
        with self.lock:
            self.logger.info(f"配置更新: {protocol} {ip}:{port}")
            self.protocol = Protocol(protocol.lower())
            self.target_ip = ip
            self.target_port = int(port)
            
            if not self._validate_config():
                self.logger.error("配置验证失败")
                return False
            
            self.stop_event.clear()
            self._start_reconnect_thread()
            return True

    def _validate_config(self):
        if not self.target_ip or not self.target_port:
            self.logger.error("IP或端口未设置")
            return False
        try:
            socket.inet_aton(self.target_ip)
        except socket.error:
            self.logger.error("无效的IP地址")
            return False
        return True

    def connect(self):
        with self.lock:
            if self.connected:
                self.logger.debug("已连接，跳过重复连接")
                return True
            
            self._cleanup_socket()
            
            try:
                if self.protocol == Protocol.TCP:
                    self._connect_tcp()
                else:
                    self._connect_udp()
                
                self.connected = True
                self.logger.info(f"成功连接到 {self.target_ip}:{self.target_port} ({self.protocol.value.upper()})")
                return True
            except Exception as e:
                self.logger.error(f"连接失败: {str(e)}")
                self.connected = False
                self._cleanup_socket()
                return False

    def _connect_tcp(self):
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.settimeout(5)
        self.socket.connect((self.target_ip, self.target_port))
        # 设置keepalive
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
        self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 30)
        self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 10)
        self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 3)

    def _connect_udp(self):
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        # UDP测试连接
        try:
            self.socket.sendto(b'\x00', (self.target_ip, self.target_port))
        except Exception as e:
            raise Exception(f"UDP测试发送失败: {str(e)}")

    def disconnect(self):
        with self.lock:
            self.logger.info("主动断开连接")
            self.stop_event.set()
            self.connected = False
            self._cleanup_socket()

    def _cleanup_socket(self):
        if self.socket:
            try:
                self.socket.close()
            except Exception as e:
                self.logger.warning(f"关闭socket时出错: {str(e)}")
            finally:
                self.socket = None

    def reconnect(self):
        self.logger.debug("重连线程启动")
        while not self.stop_event.is_set():
            if not self.connected and self.target_ip and self.target_port:
                self.logger.debug("尝试重新连接...")
                self.connect()
            time.sleep(2)
        self.logger.debug("重连线程退出")

    def _start_reconnect_thread(self):
        if self.reconnect_thread and self.reconnect_thread.is_alive():
            self.logger.debug("已有活跃的重连线程")
            return
            
        self.reconnect_thread = threading.Thread(
            target=self.reconnect,
            name="ReconnectThread",
            daemon=True
        )
        self.reconnect_thread.start()
        self.logger.debug("启动新的重连线程")

    def get_status(self):
        with self.lock:
            return {
                'connected': self.connected,
                'protocol': self.protocol.value,
                'ip': self.target_ip,
                'port': self.target_port,
                'thread_alive': self.reconnect_thread.is_alive() if self.reconnect_thread else False,
                'target_valid': bool(self.target_ip and self.target_port)
            }

    def send_data(self, data):
        with self.lock:
            if not self.connected or not self.socket:
                self.logger.warning("发送失败: 未连接")
                return False
            
            try:
                if self.protocol == Protocol.TCP:
                    self.socket.sendall(data.encode())
                else:
                    self.socket.sendto(data.encode(), (self.target_ip, self.target_port))
                return True
            except Exception as e:
                self.logger.error(f"发送数据失败: {str(e)}")
                self.connected = False
                return False